﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AssetManagementSystem.Model;
using AssetManagementSystem.Utils.Events;
using AssetManagementSystem.View.IView;
using AssetManagementSystem.Utils;
using AssetManagementSystem.Model.Notification;

namespace AssetManagementSystem.Presenter {
    class LoanPresenter {

        LoanManager manager;
        ILoanView view;

        public LoanPresenter(ILoanView view) {
            manager = new LoanManager();
            this.view = view;
            //Handle Loan View Events
            this.view.Loans_LoadAll += new EventHandler(PresentAllLoans);
            this.view.Loans_Find += new EventHandler<SearchEventArgs>(PresentFoundLoans);
            this.view.Loan_Create += new EventHandler<LoanEventArgs>(CreateLoan);
            this.view.Loan_Return += new EventHandler<LoanEventArgs>(ReturnLoan);
            this.view.LoanAsset_Return += new EventHandler<LoanAssetEventArgs>(ReturnLoanAsset);
            this.view.LoanAssets_LoadAvailable += new EventHandler(PresentAvailableAssets);
            this.view.Loan_Notify += new EventHandler<LoanEventArgs>(SendOverdueNotification);
        }

        private void PresentAvailableAssets(object sender, EventArgs e) {
            AssetManager tmpMan = new AssetManager();
            List<Asset> tmpList = new List<Asset>();
            foreach(Asset asset in tmpMan.GetAllAssets()){
                if(manager.isLoanAssetAvailable(asset.Id))
                    tmpList.Add(asset);
            }
            view.SetAvailableAssets(tmpList);
        }

        private void SendOverdueNotification(object sender, LoanEventArgs e) {
            StudentManager tmpMan = new StudentManager();
            Loan loan = e.Loan;
            Student student = tmpMan.GetStudent(loan.StudentId);
            try {
                NotificationAssistant.SendNotification(student, loan);
                DialogResult dialogResult = MessageBox.Show("Notification Sent.", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information);
            } catch (Exception sendError) {
                DialogResult dialogResult = MessageBox.Show("Notification Failed: " + sendError.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        /// <summary>
        /// Provides a list of all loans to the view for display
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event args</param>
        private void PresentAllLoans(object sender, EventArgs e) {
            view.SetLoanList(manager.GetAllLoans());
        }

        /// <summary>
        /// Provides a list of loans found based on search data provided in event args
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">event args, must contain search input</param>
        private void PresentFoundLoans(object sender, SearchEventArgs e) {
            view.SetLoanList(manager.FindLoans(e.SearchText));
        }

        /// <summary>
        /// Tries to create a new loan and refresh the view
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">args</param>
        private void CreateLoan(object sender, LoanEventArgs e) {
            try {

                //Check if the user would like to generate loan agreements
                DialogResult dialogResult = MessageBox.Show("Would you like to generate agreements or other forms, for one or more of the assets in this loan?", 
                    "Generate Agreements", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (dialogResult == DialogResult.Yes) {
                    AssetManager tmpMan = new AssetManager();
                    StudentManager tmpStuMan = new StudentManager();
                    //Check which asset to generate agreements for.
                    foreach (KeyValuePair<string, DateTime> loanAsset in e.Loan.Assets) {
                        try{
                            Asset tmpAsset = tmpMan.GetAsset(loanAsset.Key);
                            Student tmpStudent = tmpStuMan.GetStudent( e.Loan.StudentId );
                            dialogResult = MessageBox.Show("Generate agreement or form for " + 
                                tmpAsset.Name + 
                                " - [" + tmpAsset.Id +
                                "]?",  
                                "Generate Agreements", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                            while (dialogResult == DialogResult.Yes) {
                                AssetManagementSystem.Model.Agreement.DocumentAssistant.SelectAndGenerate(GenerateAgreementFields(e.Loan, tmpAsset, tmpStudent));
                                dialogResult = MessageBox.Show("Generate another agreement or form for " +
                                    tmpAsset.Name +
                                    " - [" + tmpAsset.Id +
                                    "]?",
                                "Generate Agreements", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                            }
                        }catch(Exception findEx){

                        }
                    }
                }

                //store the new loan
                manager.CreateLoan(e.Loan);
                //refresh the loans on the view
                PresentAllLoans(this, null);
                view.ShowMessage("Loan successfully saved.");
            } catch (Exception createFailed) {
                //if something goes wrong, send a message to the view
                view.ShowMessage(createFailed.Message);
            }
        }

        private Dictionary<string, string> GenerateAgreementFields(Loan loan, Asset asset, Student student) {
            Dictionary<string, string> fields = new Dictionary<string, string>();
            fields.Add("<<[Loan.DueDate]>>", loan.DueDate.ToString("dd/MM/yyyy"));
            fields.Add("<<[Loan.StartDate]>>", loan.StartDate.ToString("dd/MM/yyyy"));

            fields.Add("<<[Student.Id]>>", student.StudentId );
            fields.Add("<<[Student.FirstName]>>", student.FirstName);
            fields.Add("<<[Student.LastName]>>", student.LastName);
            fields.Add("<<[Student.Email]>>", student.EmailAddress);

            fields.Add("<<[Asset.Name]>>", asset.Name);
            fields.Add("<<[Asset.Id]>>", asset.Id);
            fields.Add("<<[Asset.GroupName]>>", asset.GroupName);
            fields.Add("<<[Asset.Description]>>", asset.Description);

            foreach (KeyValuePair<string, string> prop in asset.Properties) {
                fields.Add("<<[Asset.Property." + prop.Key + "]>>", prop.Value);
            }

            return fields;
        }

        /// <summary>
        /// Tries to update an existing loan and refresh the view
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">args</param>
        private void UpdateLoan(object sender, LoanEventArgs e) {
            try {
                //update the loan
                manager.UpdateLoan(e.Loan);
                //refresh the loans on the view
                PresentAllLoans(this, null);
                view.ShowMessage("Loan successfully updated.");
            } catch (Exception updateFailed) {
                //if something goes wrong, send a message to the view
                view.ShowMessage(updateFailed.Message);
            }
        }

        /// <summary>
        /// Tries to return all assets in an existing loan and refresh the view
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">args</param>
        private void ReturnLoan(object sender, LoanEventArgs e) {
            try {
                //return the loan
                manager.ReturnLoan(e.Loan);
                //refresh the loans on the view
                PresentAllLoans(this, null);
                view.ShowMessage("Loan successfully returned.");
            } catch (Exception deleteFailed) {
                //if something goes wrong, send a message to the view
                view.ShowMessage(deleteFailed.Message);
            }
        }

        /// <summary>
        /// Tries to return an asset in an existing loan and refresh the view
        /// </summary>
        /// <param name="sender">event sender</param>
        /// <param name="e">args</param>
        private void ReturnLoanAsset(object sender, LoanAssetEventArgs e) {
            try {
                //return the loan asset
                manager.ReturnLoanAsset(e.Loan, e.AssetId);
                //refresh the loans on the view
                PresentAllLoans(this, null);
            } catch (Exception deleteFailed) {
                //if something goes wrong, send a message to the view
                view.ShowMessage(deleteFailed.Message);
            }
        }

    }
}
